#include "frame_drive.h"
#include "string.h"


// 帧解析函数 （从Fifo中解析帧） 
void FRAME_FrameDecode(FIFO_STATE *state,FRAME_FRAME_CB *frame ,FRAME_FIFO_CB *fifo,uint8_t (*FrameCheckValue)(FRAME_FRAME_CB *frame))
{
	// 解码数据 0x55 0x00 0x0a     0x1E    0x02      0x01   0x01     0x01     0x02  0xbf
	//     帧头 └-----------┘     命令字   长度  其他内容 其他内容      └-----┘     校验

	// 需要定义帧头，只需要第一个字节内容        FRAME_CMD_STX  0x55   // 帧头
	// 需要定义帧长度所在下标位置                FRAME_LEN_POS  6 
	// 需要定义计算帧总长度函数(传入帧长度)      FRAME_GET_TOT_LEN(x)    (x + 8)  //帧总长度
	// 需要定义帧校验码所在下标位置(传入帧长度)  FRAME_GET_CHECK_POS(x)  (x + 7)  //帧校验值所在下标位置
	
	// 解码使用状态机解码:
	// 1.寻找帧头状态
	// 2.寻找帧长度状态
	// 3.寻找帧尾状态
	// 4.校验帧状态
	//  根据实际帧情况，安排各个状态执行内容
	
	uint8_t temp;
	uint8_t ch;
	uint8_t check;
	uint8_t result;
	FRAME_FRAME_CB tempFrame;
	// Fifo空，无可以解析的数据
	if(FRAME_FifoIsEmpty(fifo)) return;
	
	switch(*state)
	{
		case FIFO_STATE_FIND_STX:
			FRAME_FifoGet(&ch,0,fifo);
			if(FRAME_CMD_STX == ch) // 找到帧头
			{
				 *state = FIFO_STATE_FIND_LEN;
					// 状态转移到计算len 位置		
			}
			else // 未找到帧头，将Fifo头Pop
			{
			   FRAME_FifoPop(&temp,fifo);				
			}
			
			break;
		case FIFO_STATE_FIND_LEN:
			if(fifo->length > FRAME_LEN_POS)
			{
				// len = 长度; 
				//#warning "这里其实有bug  万一数据长度不合法并且很长 那么将会一直等待很长的数据才解析"
				FRAME_FifoGet(&temp,FRAME_LEN_POS,fifo);
				temp = FRAME_GET_TOT_LEN(temp);	
				if(fifo->length >=temp)
					*state = FIFO_STATE_FIND_EXT;
			}
			break;
			
		case FIFO_STATE_FIND_EXT:
			  // 跳转校验
			   *state = FIFO_STATE_CHECK_FRAM;
			
					break;
		case FIFO_STATE_CHECK_FRAM:
			
		     // 获取数据长度到 temp
		     FRAME_FifoGet(&temp,FRAME_LEN_POS,fifo);
		    
		     // 计算帧总长度
		     tempFrame.length = FRAME_GET_TOT_LEN(temp);	     
		
		     // 将帧复制到临时帧变量中
			   FRAME_FifoCopy((uint8_t *)tempFrame.buff,tempFrame.length,fifo);
		
		     // 获取校验值到 check
		     FRAME_FifoGet(&check,FRAME_GET_CHECK_POS(temp),fifo);
		     
		     // 计算校验值
		     result = FrameCheckValue(&tempFrame);
		    
		     if(check == result) // 校验成功
				 {					 
					 //frame 赋值
					 memcpy(frame,&tempFrame,sizeof(FRAME_FRAME_CB));
					 
					 //Fifo 移除解析到的帧
					 FRAME_FifoRemove(frame->length,fifo);
					 
				 }
				 else // 抛弃头 准备检查下一个头
				 {
				      FRAME_FifoPop(&temp,fifo);	
							
				 }
		     *state = FIFO_STATE_FIND_STX;
			break;
	
	}
}

// 校验码计算函数
uint8_t FrameCheck(FRAME_FRAME_CB *frame)
{
	uint8_t cc = 0;
    uint16_t i = 0;
   
    // 从命令头开始，到校验码之前的一个字节，依次进行异或运算
    for(i = 0; i < frame->length -1; i++)
    {
        cc ^= frame->buff[i];
    }
    cc = ~cc;
    return cc;
}


// 以下部分请勿修改
// ------- 模块实现函数部分 -------

// 初始化函数     main() 调用   参数: 帧解析函数,校验码计算函数,帧指令处理函数
void FRAME_Init(FRAME_DEVICE_CB *driver ,void (*Decode)(FIFO_STATE *state,FRAME_FRAME_CB *frame ,FRAME_FIFO_CB *fifo,uint8_t (*FrameCheckValue)(FRAME_FRAME_CB *frame)),uint8_t (*Check)(FRAME_FRAME_CB *frame),void (*FrameCmd)(FRAME_FRAME_CB *frame,FRAME_DEVICE_CB *device))
{
	// 初始化结构体
	FRAME_FifoInit(&driver->fifo_rx);
	FRAME_FifoInit(&driver->fifo_tx);
	FRAME_FrameQueueInit(&driver->queue_rx);
	FRAME_FrameQueueInit(&driver->queue_tx);
	// 初始化函数指针
	driver->Busy = false;
	driver->FrameProcessDecode = Decode;
	driver->FrameCheckValue = Check;
	driver->FrameProcessCmd = FrameCmd;	
	
}

// 处理线程函数   while  中调用
void FRAME_Process(FRAME_DEVICE_CB *driver)
{
	// 解码 （执行用户帧解码处理函数）
	uint8_t data = 0;
	FRAME_FRAME_CB tempFrame;
	tempFrame.length = 0;
	
	driver->FrameProcessDecode(&driver->fifoState ,&tempFrame,&driver->fifo_rx,driver->FrameCheckValue);
	
	if(tempFrame.length != 0)  // 帧解析成功
	{
		// 加入到 FrameQueue
		FRAME_FramePushQueue(&tempFrame,&driver->queue_rx);
		
	}
	
	// 指令处理 （执行用户指令处理函数）
	if(FRAME_FramePopQueue(&tempFrame,&driver->queue_rx))
	{
		driver->FrameProcessCmd(&tempFrame,driver);
	}
	

	
	// 将待发送帧队列的数据添加到发送Fifo中
	while((!FRAME_FifoIsFull(&driver->fifo_tx)) &&  (FRAME_FrameQueueGetSendChar(&driver->queue_tx,&data)))
	{
		//发送Fifo不满，并且有可以取出的字符
		//取出一个当前的数据
		FRAME_FifoPush(data,&driver->fifo_tx);
	
	}
	
}


// ------- frame 函数 -------

// 帧初始化
bool FRAME_FrameInit(FRAME_FRAME_CB *frame)
{
	memset((void *)frame->buff,0,sizeof(frame->buff));
	frame->deviceID = 0;
	frame->length = 0;
	return true;
}

// 帧队列初始化
bool FRAME_FrameQueueInit(FRAME_FRAME_QUEUE *queue)
{
	uint8_t i = 0;
	for(i = 0;i < FRAME_FRAME_QUEUE_SIZE;i++)
	{
		FRAME_FrameInit(&queue->queue[i]);		
	}	
	
	queue->head = 0;
	queue->end = 0;
	queue->index = 0;
	
	return true;
}


// 加入帧到队列(用于转发)
bool FRAME_FramePushQueue(FRAME_FRAME_CB *frame,FRAME_FRAME_QUEUE *queue)
{
		// USART
	if(FRAME_FrameQueueIsFull(queue)) return false;
	// 将接收到的数据放到Fifo中
	memcpy(&queue->queue[queue->end].buff, (void *)frame->buff, frame->length);
	queue->queue[queue->end].length = frame->length;
	queue->queue[queue->end].deviceID = frame->deviceID;

	queue->end++;
	queue->end %= FRAME_FRAME_QUEUE_SIZE;
	return true;
}

// 从帧队列中Pop一个帧
bool FRAME_FramePopQueue(FRAME_FRAME_CB *frame,FRAME_FRAME_QUEUE *queue)
{
	if(FRAME_FrameQueueIsEmpty(queue)) return false;
	
	memcpy(&frame->buff,&queue->queue[queue->head].buff,queue->queue[queue->head].length);
	frame->length = queue->queue[queue->head].length;
	frame->deviceID = queue->queue[queue->head].deviceID;
	
	queue->head++;
	queue->head %= FRAME_FRAME_QUEUE_SIZE;
  return true;
}
// 判断FrameQueue 是否空。  Fifo空：True  未空：False
bool FRAME_FrameQueueIsEmpty(FRAME_FRAME_QUEUE *queue)
{
	if (queue->end == queue->head)
		return true;
	else 
		return false;
}

// 判断FrameQueue 是否满。  Fifo满：True  未满：False
bool FRAME_FrameQueueIsFull(FRAME_FRAME_QUEUE *queue)
{
	if (queue->end + 1 % FRAME_FRAME_QUEUE_SIZE == queue->head)
		return true;
	else 
		return false;
}


// 判断FrameQueue 发送索引是否到结尾  到达帧尾：True, 未到达帧尾:False
bool FRAME_FrameQueueIndexIsTail(FRAME_FRAME_QUEUE *queue)
{
	if(queue->index >= queue->queue[queue->head].length) return true;
	else return false;
}

// 获取队列中一个要发送的字符
bool FRAME_FrameQueueGetSendChar(FRAME_FRAME_QUEUE *queue,uint8_t *ch)
{
	FRAME_FRAME_CB frame;
	if(FRAME_FrameQueueIsEmpty(queue)) return false;
	if(queue->index >= queue->queue[queue->head].length) 
	{
		queue->index = 0;
		FRAME_FramePopQueue(&frame,queue);
		return false;
	}
	else
	{
		*ch = queue->queue[queue->head].buff[queue->index++];		
		return true;
	
	}
}


// ------- fifo 函数 -------


// 将一个字节存入Fifo中。  成功：True, 失败 ：False
bool FRAME_FifoPush(uint8_t ch,FRAME_FIFO_CB *fifo)
{
	if(FRAME_FifoIsFull(fifo)) return false;
	
	 // 将接收到的数据放到Fifo中
	fifo->buff[fifo->end] = ch;
	fifo->end ++;
	fifo->end %= FRAME_FIFO_SIZE;
	fifo->length ++;
	return true;
}


// 取出Fifo 实现
bool FRAME_FifoPop(uint8_t *ch,FRAME_FIFO_CB *fifo)
{
	*ch = fifo->buff[fifo->head];
	fifo->head++;
	fifo->head %= FRAME_FIFO_SIZE;
	fifo->length --;
	return true;
}

// Fifo结构体初始化
void FRAME_FifoInit(FRAME_FIFO_CB *fifo)
{
	memset(&fifo->buff,0,sizeof(fifo->buff));
	fifo->end = 0;
	fifo->head = 0;
	fifo->length = 0;
}

// 判断Fifo 是否空。  Fifo空：True  未空：False
bool FRAME_FifoIsEmpty(FRAME_FIFO_CB *fifo)
{
	if (fifo->end == fifo->head)
		return true;
	else 
		return false;
}

// 判断Fifo 是否满。  Fifo满：True  未满：False
bool FRAME_FifoIsFull(FRAME_FIFO_CB *fifo)
{
	if (fifo->end + 1 % FRAME_FIFO_SIZE == fifo->head)
		return true;
	else 
		return false;
}

// 从Fifo中取出第N位置的字符。  成功：True, 失败 ：False
bool FRAME_FifoGet(uint8_t *ch,uint8_t pos ,FRAME_FIFO_CB *fifo)
{
	int temp = 0;
	if(pos > fifo->length ) return false;
	temp = (fifo->head + pos) % FRAME_FIFO_SIZE;
	*ch = fifo->buff[temp];
	return true;    	
}

// 从Fifo中取出第N个字符到buf。  成功：True, 失败 ：False
bool FRAME_FifoCopy(uint8_t *buf,uint8_t len ,FRAME_FIFO_CB *fifo)
{
	int i=0;
	if(len > fifo->length ) return false;

	while(i<len)
	{
		FRAME_FifoGet(buf,i,fifo);
		buf++;
		i++;

	}	

	return true;
}

// 从Fifo中移除N个字符。  成功：True, 失败 ：False
bool FRAME_FifoRemove(uint8_t len ,FRAME_FIFO_CB *fifo)
{
	uint8_t temp;
	if(len>fifo->length) return false;
	while(len)
	{
		FRAME_FifoPop(&temp,fifo);
		len--;
	}
	return true;
}

